package com.sunsharing.transport.mina;

import com.sunsharing.common.Constant;
import com.sunsharing.common.ContextCreate;
import com.sunsharing.common.URL;
import com.sunsharing.common.anno.Factory;
import com.sunsharing.common.mailbox.QueueHandle;
import com.sunsharing.transport.*;
import org.apache.log4j.Logger;
import org.apache.mina.core.RuntimeIoException;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

import java.net.InetSocketAddress;
import java.util.Iterator;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created with IntelliJ IDEA.
 * User: criss
 * Date: 13-3-31
 * Time: 下午8:56
 * To change this template use File | Settings | File Templates.
 */
@Factory(key="MINA")
public class MinaClient  implements Client {

    Logger logger = Logger.getLogger(MinaClient.class);

    NioSocketConnector connector = null;
    LongChannel channel;
    static Lock lock =  new ReentrantLock();

    @Override
    public Channel connect(URL url,IoHandle handler) {
        MinaChannel client = (MinaChannel)ConnectClients.searchClient(Constant.PROTOCOL_MINA,url.getIp(),url.getPort());

        if(client!=null && !client.isclose())
        {
            logger.warn(client.url+"已经连接过了，不需要再连接了,当前状态:"+client.isclose());
            return client;
        }

        /*ByClient模式有问题,后面再考虑*/
        /*boolean byClient = searchByClient(url.getProtocol(),url.getIp());
        if(byClient)
        {
            logger.warn(channel.url+"禁用连接，客户端为ByClient模式，不允许服务端连接");
            MinaChannel minaChannel = (MinaChannel)searchClient(Constant.PROTOCOL_MINA,url.getMyNodeId(),false);
            if(minaChannel!=null)
            {
                channel = minaChannel;
            } else
            {
                logger.warn(channel.url+"禁用连接，客户端为ByClient模式，不允许服务端连接,并且无客户端连接");
                channel = null;
            }
            return minaChannel;
        }*/


        lock.lock();
        //连接到服务器
        try {
            //Create TCP/IP connection
            NioSocketConnector connector = new NioSocketConnector();

            SocketSessionConfig cfg = connector.getSessionConfig();
            cfg.setTcpNoDelay(true);
            cfg.setKeepAlive(true);
            cfg.setIdleTime(IdleStatus.BOTH_IDLE, 60);

            //创建接受数据的过滤器
            DefaultIoFilterChainBuilder chain = connector.getFilterChain();

            //设定这个过滤器将一行一行(/r/n)的读取数据
            chain.addLast("codec", new ProtocolCodecFilter(new MyProtocolCodecFactory()));
            //服务器的消息处理器：一个SamplMinaServerHander对象
            connector.setHandler(new MinaIoHandler(handler,true,url));

            //set connect timeout
            connector.setConnectTimeoutMillis(5000);
            ConnectFuture future = connector.connect(new InetSocketAddress(url.getIp(),url.getPort()));
            future.awaitUninterruptibly();
            IoSession s = future.getSession();
            s.write(ContextCreate.createConnectContext(url.toString()));
            MinaChannel minaChannel = (MinaChannel)searchChannelBySession(s);
            return null;
        } catch (RuntimeIoException e) {
            logger.info("连接服务端出错",e);
            throw new RuntimeException("连接服务器出错,IP:"+url);
        }finally {
            lock.unlock();
        }
    }

    @Override
    public void close() {
        try
        {
            connector.dispose();
        }catch (Exception e)
        {

        }finally {
            ConnectClients.removeClient(channel);
        }
    }
    public Channel searchChannelBySession(IoSession s)
    {
        Channel rst = null;
        for(Iterator<Channel> iter = ConnectClients.activeClients.iterator();iter.hasNext();)
        {
            Channel c = (Channel)iter.next();

            if(c instanceof MinaChannel)
            {
                //logger.error("查找session:"+((MinaChannel)c).session);
                if(s==((MinaChannel)c).session)
                {

                    rst = c;
                }
            }
        }
        return rst;
    }


}
